
package com.hlkj.pay.app.order.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.util.ArrayList;
import java.util.List;

import javax.validation.Valid;

import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.pojo.LocalContext;
import com.hlkj.framework.common.util.id.IdUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.ext.dto.profit.ChannelSubsidyOrderContext;
import com.hlkj.pay.app.order.ISubsidyOrderAppService;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.common.OpenApiResultCode;
import com.hlkj.pay.dto.order.OrderSubsidyDto;
import com.hlkj.pay.dto.order.PayOrderSubsidyDto;
import com.hlkj.pay.dto.order.RefundOrderSubsidyDto;
import com.hlkj.pay.dto.order.SubsidyOrderResultDto;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.gateway.order.IChannelSubsidyOrderGateway;
import com.hlkj.pay.infrastructure.model.order.OrderSubsidyDO;
import com.hlkj.pay.infrastructure.model.order.OrderSubsidyDetailDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.service.order.IPayOrdeSubsidyService;
import com.hlkj.pay.service.order.IPayOrderService;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.vo.openapi.order.resp.SubsidyOrderApiResp;
import com.hlkj.pay.vo.openapi.order.resp.SubsidyOrderDetailResp;
import com.hlkj.pay.vo.openapi.order.resp.SubsidyRefundOrderApiResp;
import com.hlkj.pay.vo.order.req.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2025/01/07 11:22
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Validated
public class SubsidyOrderAppServiceImpl implements ISubsidyOrderAppService {

    private final IPayOrderService payOrderService;

    private final IChannelSubsidyOrderGateway channelSubsidyOrderGateway;

    private final OrderNotifyHandler orderNotifyHandler;

    private final IPayOrdeSubsidyService payOrdeSubsidyService;

    @Override
    public CommonResult<SubsidyOrderApiResp> submitSubsidyOrder(@Valid SubsidyOrderParamReq subsidyPayOrderParamReq) {
        log.info("submitSubsidyOrder subsidyPayOrderParamReq:{}", JsonUtils.toJsonString(subsidyPayOrderParamReq));
        try {
            // 查询订单信息
            PayOrderDO payOrderDO = null;
            if (StringUtils.hasText(subsidyPayOrderParamReq.getPayOrderNo())) {
                payOrderDO = payOrderService.queryPayOrderNoCache(subsidyPayOrderParamReq.getPayOrderNo());
            }
            else {
                String sn = LocalContext.get().getSn();
                payOrderDO = payOrderService.queryPayOrderByMerOrderNo(sn, subsidyPayOrderParamReq.getMchOrderNo());
            }
            if (payOrderDO == null) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_FUND_DATA_ERROR);
            }
            // 订单是否支付完成
            if (!PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode().equals(payOrderDO.getState())) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_SUBSIDY_ORDER_NOT_EFFECT);
            }
            // 通道实现校验
            if (!channelSubsidyOrderGateway.extensionExist(payOrderDO.getChannelCode())) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_SUBSIDY_ORDER_NOT_EFFECT);
            }
            // 是否清算完成  注：营销补贴必须要订单清算完成
            if(payOrderDO.getCsState() == null ||  payOrderDO.getCsState() != 1){
                return CommonResult.error(OpenApiResultCode.MERCHANT_SUBSIDY_CS_NOT_COMPLETED);
            }

            // 营销补贴信息
            OrderPromotionInfo promotionInfo = subsidyPayOrderParamReq.getPromotionInfo();

            ChannelSubsidyOrderContext channelSubsidyOrderContext = new ChannelSubsidyOrderContext();
            channelSubsidyOrderContext.setPayOrderDO(payOrderDO);

            List<PayOrderSubsidyDto> payOrderSubsidyDtoList = new ArrayList<>();
            // 生成批次号
            String batchNo = IdUtils.getSnowflakeNextIdStr();
            PayOrderSubsidyDto payOrderFundDto = BeanUtil.copyProperties(promotionInfo, PayOrderSubsidyDto.class);
            payOrderFundDto.setBatchNo(batchNo);
            payOrderFundDto.setBatchNoDetail(batchNo + "_" + 1);
            payOrderSubsidyDtoList.add(payOrderFundDto);
            channelSubsidyOrderContext.setPayOrderSubsidyDtoList(payOrderSubsidyDtoList);
            // 请求第三方
            SubsidyOrderResultDto subsidyOrderResultDto = channelSubsidyOrderGateway.submitSubsidyOrder(channelSubsidyOrderContext);
            if (PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.FAIL.getCode().equals(subsidyOrderResultDto.getPayOrderSubsidyStatus().getCode())) {
                SubsidyOrderApiResp subsidyOrderApiResp = new SubsidyOrderApiResp();
                subsidyOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
                subsidyOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
                // 返回支付数据
                CommonResult<SubsidyOrderApiResp> error = null;
                if(StrUtil.isNotEmpty(subsidyOrderResultDto.getRemark())){
                    error = CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_SUBSIDY_ERROR.getCode(),subsidyOrderResultDto.getRemark());
                    error.setData(subsidyOrderApiResp);
                }else{
                    error = CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_SUBSIDY_ERROR);
                    error.setData(subsidyOrderApiResp);
                }
                return error;
            }
            // 回写数据
            payOrdeSubsidyService.addSubsidyInfo(subsidyPayOrderParamReq, payOrderSubsidyDtoList, payOrderDO);

            SubsidyOrderApiResp subsidyOrderApiResp = new SubsidyOrderApiResp();
            SubsidyOrderDetailResp detailResp = BeanUtil.copyProperties(promotionInfo,SubsidyOrderDetailResp.class);
            subsidyOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
            subsidyOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
            subsidyOrderApiResp.setBatchNo(batchNo);
            subsidyOrderApiResp.setDetailResp(detailResp);
            return CommonResult.success(subsidyOrderApiResp);
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<SubsidyRefundOrderApiResp> refundSubsidyOrder(@Valid SubsidyRefundOrderParamReq subsidyRefundOrderParamReq) {
        log.info("refundSubsidyOrder subsidyRefundOrderParamReq:{}", JsonUtils.toJsonString(subsidyRefundOrderParamReq));
        try {
            OrderSubsidyDO orderSubsidyDO = payOrdeSubsidyService.queryOrderSubsidyInfo(subsidyRefundOrderParamReq.getBatchNo(), subsidyRefundOrderParamReq.getMchOrderNo());
            if (orderSubsidyDO == null) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_SUBSIDY_ORDER_NOT_EFFECT);
            }
            List<OrderSubsidyDetailDO> subsidyDetailDOList = payOrdeSubsidyService.querySubsidyDetailInfo(subsidyRefundOrderParamReq.getBatchNo());
            PayOrderDO payOrderDO = payOrderService.queryPayOrder(orderSubsidyDO.getPayOrderNo());
            // 营销补贴信息
            OrderPromotionInfo promotionInfo = subsidyRefundOrderParamReq.getPromotionInfo();

            // 组装退款集合
            List<RefundOrderSubsidyDto> refundOrderSubsidyList = new ArrayList<>();
            // 批次号生成
            String batchNo = IdUtils.getSnowflakeNextIdStr();
            OrderSubsidyDetailDO orderSubsidyDetailDO = subsidyDetailDOList.get(0);
            // 提交的金额不能大于支付的分账金额
            if (MerchantUtils.stringToBigDecimal(promotionInfo.getAmount()).compareTo(orderSubsidyDetailDO.getAmount()) > 0) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_SUBSIDY_BACK_AMOUNT_ERROR);
            }
            RefundOrderSubsidyDto refundOrderSubsidyDto = BeanUtil.copyProperties(promotionInfo, RefundOrderSubsidyDto.class);
            refundOrderSubsidyDto.setBatchNo(batchNo);
            refundOrderSubsidyDto.setBatchNoDetail(batchNo + "_" + 1);
            refundOrderSubsidyDto.setAmount(promotionInfo.getAmount());
            refundOrderSubsidyDto.setCreateTime(orderSubsidyDetailDO.getCreateTime());
            refundOrderSubsidyList.add(refundOrderSubsidyDto);
            // 请求第三方
            ChannelSubsidyOrderContext channelSubsidyOrderContext = new ChannelSubsidyOrderContext();
            channelSubsidyOrderContext.setSubsidyRequestId(subsidyRefundOrderParamReq.getBatchNo());
            channelSubsidyOrderContext.setPayOrderDO(payOrderDO);
            channelSubsidyOrderContext.setRefundOrderSubsidyDtoList(refundOrderSubsidyList);
            SubsidyOrderResultDto subsidyOrderResultDto = channelSubsidyOrderGateway.submitSubsidyRefundOrder(channelSubsidyOrderContext);

            if (PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.FAIL.getCode().equals(subsidyOrderResultDto.getPayOrderSubsidyStatus().getCode())) {
                SubsidyRefundOrderApiResp subsidyRefundOrderApiResp = new SubsidyRefundOrderApiResp();
                subsidyRefundOrderApiResp.setBatchNo(batchNo);
                subsidyRefundOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
                subsidyRefundOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
                // 返回支付数据
                CommonResult<SubsidyRefundOrderApiResp> error = null;
                if(StrUtil.isNotEmpty(subsidyOrderResultDto.getRemark())){
                    error = CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_SUBSIDY_ERROR.getCode(),subsidyOrderResultDto.getRemark());
                    error.setData(subsidyRefundOrderApiResp);
                }else{
                    error = CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_SUBSIDY_ERROR);
                    error.setData(subsidyRefundOrderApiResp);
                }
                return error;
            }
            // 更新数据
            OrderSubsidyDto orderSubsidyDto = payOrdeSubsidyService.addSubsidyRefundInfo(subsidyRefundOrderParamReq, refundOrderSubsidyList, payOrderDO,channelSubsidyOrderContext.getSubsidyRequestId());
            SubsidyRefundOrderApiResp subsidyRefundOrderApiResp = new SubsidyRefundOrderApiResp();
            subsidyRefundOrderApiResp.setBatchNo(batchNo);
            subsidyRefundOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
            subsidyRefundOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
            // 返回支付数据
            return CommonResult.success(subsidyRefundOrderApiResp);
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<SubsidyOrderApiResp> querySubsidyOrder(SubsidyOrderQueryParamReq subsidyOrderQueryParamReq) {
        log.info("querySubsidyOrder subsidyOrderQueryParamReq:{}", JsonUtils.toJsonString(subsidyOrderQueryParamReq));
        try {
            if (!StringUtils.hasText(subsidyOrderQueryParamReq.getBatchNo()) && !StringUtils.hasText(subsidyOrderQueryParamReq.getMchOrderNo())) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            OrderSubsidyDO orderSubsidyDO = payOrdeSubsidyService.queryOrderSubsidyInfo(subsidyOrderQueryParamReq.getBatchNo(), subsidyOrderQueryParamReq.getMchOrderNo());
            if (orderSubsidyDO == null) {
                return CommonResult.error(CommonResultCode.DATA_NOT_EXIST);
            }
            List<OrderSubsidyDetailDO> orderSubsidyDetailList = payOrdeSubsidyService.querySubsidyDetailInfo(subsidyOrderQueryParamReq.getBatchNo());

            PayOrderDO payOrderDO = payOrderService.queryPayOrderNoCache(orderSubsidyDO.getPayOrderNo());
            // 请求第三方
            ChannelSubsidyOrderContext channelSubsidyOrderContext = new ChannelSubsidyOrderContext();
            channelSubsidyOrderContext.setPayOrderDO(payOrderDO);
            channelSubsidyOrderContext.setOrderSubsidyDetailList(orderSubsidyDetailList);
            SubsidyOrderResultDto subsidyOrderResultDto = channelSubsidyOrderGateway.querySubsidyOrder(channelSubsidyOrderContext);
            // 更新数据
            orderSubsidyDetailList = updatePayFund(subsidyOrderResultDto.getPayOrderSubsidyList(), orderSubsidyDO);
            SubsidyOrderApiResp subsidyOrderApiResp = new SubsidyOrderApiResp();
            SubsidyOrderDetailResp detailResp = BeanUtil.copyProperties(orderSubsidyDetailList.get(0),SubsidyOrderDetailResp.class);
            subsidyOrderApiResp.setBatchNo(orderSubsidyDO.getBatchNo());
            subsidyOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
            subsidyOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
            subsidyOrderApiResp.setDetailResp(detailResp);
            // 返回支付数据
            return CommonResult.success(subsidyOrderApiResp);
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<SubsidyRefundOrderApiResp> queryRefundSubsidyOrder(SubsidyRefundOrderQueryParamReq subsidyRefundOrderQueryParamReq) {
        log.info("queryRefundSubsidyOrder subsidyRefundOrderQueryParamReq:{}", JsonUtils.toJsonString(subsidyRefundOrderQueryParamReq));
        try {
            if (!StringUtils.hasText(subsidyRefundOrderQueryParamReq.getBatchNo())) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            OrderSubsidyDO orderSubsidyDO =  payOrdeSubsidyService.queryOrderSubsidyInfo(subsidyRefundOrderQueryParamReq.getBatchNo(), null);
            if (orderSubsidyDO == null || StrUtil.isEmpty(orderSubsidyDO.getSubsidyRequestId())) {
                return CommonResult.error(CommonResultCode.DATA_NOT_EXIST);
            }
            List<OrderSubsidyDetailDO> orderSubsidyDetailList = payOrdeSubsidyService.querySubsidyDetailInfo(subsidyRefundOrderQueryParamReq.getBatchNo());
            PayOrderDO payOrderDO = payOrderService.queryPayOrder(orderSubsidyDO.getPayOrderNo());
            // 请求第三方
            ChannelSubsidyOrderContext channelSubsidyOrderContext = new ChannelSubsidyOrderContext();
            channelSubsidyOrderContext.setSubsidyRequestId(orderSubsidyDO.getSubsidyRequestId());
            channelSubsidyOrderContext.setPayOrderDO(payOrderDO);
            channelSubsidyOrderContext.setOrderSubsidyDetailList(orderSubsidyDetailList);

            SubsidyOrderResultDto subsidyOrderResultDto = channelSubsidyOrderGateway.querySubsidyRefundOrder(channelSubsidyOrderContext);
            orderSubsidyDetailList = updatePayFund(subsidyOrderResultDto.getPayOrderSubsidyList(), orderSubsidyDO);
            SubsidyRefundOrderApiResp subsidyOrderApiResp = new SubsidyRefundOrderApiResp();
            SubsidyOrderDetailResp detailResp = BeanUtil.copyProperties(orderSubsidyDetailList.get(0),SubsidyOrderDetailResp.class);
            subsidyOrderApiResp.setBatchNo(orderSubsidyDO.getBatchNo());
            subsidyOrderApiResp.setPayOrderNo(payOrderDO.getPayOrderNo());
            subsidyOrderApiResp.setMchOrderNo(payOrderDO.getMchOrderNo());
            subsidyOrderApiResp.setDetailResp(detailResp);
            // 返回支付数据
            return CommonResult.success(subsidyOrderApiResp);
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }


    List<OrderSubsidyDetailDO> updatePayFund(List<OrderSubsidyDetailDO> subsidyDetails, OrderSubsidyDO subsidyDO) {
        if (CollectionUtils.isEmpty(subsidyDetails)) {
            return payOrdeSubsidyService.querySubsidyDetailInfo(subsidyDO.getBatchNo());
        }
        OrderSubsidyDto orderSubsidyDto = payOrdeSubsidyService.updateSubsidy(subsidyDetails, subsidyDO.getBatchNo());
        OrderSubsidyDO orderSubsidyDO = orderSubsidyDto.getOrderSubsidyDO();
        if (orderSubsidyDO != null) {
            // 发送通知
            if (StringUtils.hasText(orderSubsidyDO.getNotifyUrl())) {
                orderNotifyHandler.orderNotify(orderSubsidyDO.getBatchNo(), 1,PayOrderEnums.ORDER_STATUS_TYPE.SUBSIDY_ORDER_STATUS);
            }
            else {
                log.info("申请营销补贴状态结束,没有填写回调通知地址,结束通知");
            }
        }
        return orderSubsidyDto.getOrderSubsidyDetailList();
    }
}
